﻿using Dapper;
using DataServer.ApplicationLib.Repositories;
using Microsoft.Extensions.DependencyInjection;
using System.Text;
using Swimj.DataCore;

namespace DataServer.ApplicationLib.Rules
{
    public class ConfigDataRuleKey : ConfigDataRuleBase
    {
        private int totalRepeated = 0;

        public IConfigDataRepository ConfigDataRepo
        {
            get
            {
                return RuleContext.ServiceProvider.GetRequiredService<IConfigDataRepository>();
            }
        }

        public ConfigDataRuleKey(RuleContext ruleContext) : base(ruleContext)
        {
        }

        public async override Task<VerifyRuleResult> VerifyData()
        {
            VerifyRuleResult verifyRuleResult = new VerifyRuleResult();
            if (RuleContext.ConfigInfo.CheckWay == DataCheckWay.InDB)
            {
                verifyRuleResult = VerifyInDB();
            }
            else
            {
                //VerifyRuleResult = VerifyInMemory();
            }

            if (this.Successor != null)
            {
                var successorResult = await this.Successor.VerifyData();
                verifyRuleResult.Message += successorResult.Message;
            }
            verifyRuleResult.IsValid = string.IsNullOrEmpty(verifyRuleResult.Message);
            return verifyRuleResult;
        }

        //private void CheckSameBatchBySearchCreteria(DataTable data, ConfigDataSameBatchSearchCriteria searchCreteria, string invalidMsg)
        //{
        //    var searchResult = this.ConfigDataRepo.SearchSameBatchData(searchCreteria);
        //    if (null != searchResult && searchResult.AmountSum > 0)
        //    {
        //        IList<ApsCmConfigDataDto> dtoList;
        //        if (RuleContext.FilterDataID.HasValue)
        //        {
        //            dtoList = AutoMapper.Mapper.Map<IList<ApsCmConfigDataDto>>(searchResult.Result.Where(d => d.Id != Context.FilterDataID.Value));
        //        }
        //        else
        //        {
        //            dtoList = AutoMapper.Mapper.Map<IList<ApsCmConfigDataDto>>(searchResult.Result);
        //        }

        //        DataTable sameBatchData = ClassInstance.ToDataTable<ApsCmConfigDataDto>(dtoList.ToArray());
        //        // 同批次的校验
        //        if (null != sameBatchData && sameBatchData.Rows.Count > 0)
        //        {
        //            var keyCols = this.RuleContext.ConfigFieldInfos.Where(f => f.IsKey && f.IsVisible).Select(f => f.ValueColumnMap);
        //            sameBatchData = sameBatchData.DefaultView.ToTable(true, keyCols.ToArray());
        //            foreach (DataRow row in sameBatchData.Rows)
        //            {
        //                string selectStr = GetSelectStr(row);
        //                if (!string.IsNullOrEmpty(selectStr))
        //                {
        //                    var invalidRows = data.Select(selectStr);
        //                    if (null != invalidRows)
        //                    {
        //                        foreach (DataRow invalidRow in invalidRows)
        //                        {
        //                            invalidRow[VerifyResultColumns.IsValid] = VerifyResultColumns.InvalidVal;
        //                            invalidRow[VerifyResultColumns.Message] = invalidRow[VerifyResultColumns.Message].ToString() + invalidMsg;
        //                            totalRepeated++;
        //                        }
        //                    }
        //                }
        //            }
        //        }
        //    }
        //}

        //private void DataBaseOnlineCheck(DataTable data)
        //{
        //    var searchCreteria = new ConfigDataSameBatchSearchCriteria
        //    {
        //        ConfigCode = this.RuleContext.ConfigInfo.ConfigCode,
        //        EnabledFlag = AutoMapper.Mapper.Map<string>(true)
        //    };
        //    int pageSize = 1;
        //    if (this.RuleContext.CurUserOpType == UserOperationType.Update || this.RuleContext.CurUserOpType == UserOperationType.Check)
        //    {
        //        pageSize = data.Rows.Count + 1;
        //    }
        //    searchCreteria.Paging = new FMS.Framework.DataModel.Paging()
        //    {
        //        PageNumber = 1,
        //        PageSize = pageSize
        //    };
        //    var primaryKeyCols = this.RuleContext.ConfigFieldInfos.Where(f => f.IsKey && f.IsVisible).Select(f => f.ValueColumnMap);
        //    string invalidMsg = string.Format("以下几列 [{0}] 组合，在数据库中已存在;", this.RuleContext.ConfigFieldInfos.Where(f => f.IsKey && f.IsVisible).Select(f => f.FieldName).ListToString());

        //    if (data.TableName != "DWAPSDATA.APS_CM_CONFIG_DATA")
        //    {

        //        for (int i = 0; i < data.Rows.Count; i++)
        //        {
        //            StringBuilder sb = new StringBuilder();
        //            sb.Append(string.Format("SELECT ID FROM {0} WHERE 1=1 ", data.TableName));
        //            sb.Append(string.Format(" AND {0} != {1} ", Tencent.OA.FDW.CM.Entity.Mappings.ApsCmConfigDataTable.Id, this.Context.FilterDataID.ToSafeInt(0)));
        //            List<string> extraCondList = new List<string>();
        //            DataRow row = data.Rows[i];

        //            foreach (var key in primaryKeyCols)
        //            {
        //                if (row[key] != null && !string.IsNullOrEmpty(row[key].ToSafeString()))
        //                {
        //                    sb.Append(string.Format(" AND {0} = '{1}' ", key, row[key]));
        //                }
        //                else
        //                {
        //                    sb.Append(string.Format(" AND {0} IS NULL ", key));
        //                }
        //            }

        //            var isHave = this.ConfigDataRepo.Exists(sb.ToString());
        //            if (isHave)
        //            {
        //                row[VerifyResultColumns.IsValid] = VerifyResultColumns.InvalidVal;
        //                row[VerifyResultColumns.Message] = row[VerifyResultColumns.Message].ToString() + invalidMsg;
        //                totalRepeated++;
        //            }
        //        }
        //    }
        //    else
        //    {
        //        for (int i = 0; i < data.Rows.Count; i++)
        //        {
        //            List<string> extraCondList = new List<string>();
        //            extraCondList.Add(string.Format("{0} != {1} ", Tencent.OA.FDW.CM.Entity.Mappings.ApsCmConfigDataTable.Id, this.Context.FilterDataID.ToSafeInt(0)));
        //            DataRow row = data.Rows[i];
        //            foreach (var key in primaryKeyCols)
        //            {
        //                if (row[key] != null && !string.IsNullOrEmpty(row[key].ToSafeString()))
        //                {
        //                    searchCreteria[key] = row[key];
        //                }
        //                else
        //                {
        //                    extraCondList.Add(string.Format("{0} IS NULL ", key));
        //                }
        //            }

        //            var searchResult = this.ConfigDataRepo.SearchSameBatchData(searchCreteria, extraCondList.ListToString(" AND "));
        //            if (null != searchResult && searchResult.Result.Count() > 0)
        //            {
        //                row[VerifyResultColumns.IsValid] = VerifyResultColumns.InvalidVal;
        //                row[VerifyResultColumns.Message] = row[VerifyResultColumns.Message].ToString() + invalidMsg;
        //                totalRepeated++;
        //            }
        //        }
        //    }
        //}

        //private void DataBaseOfflineCheck(System.Data.DataTable data)
        //{
        //    var searchCreteria = new ConfigDataSameBatchSearchCriteria
        //    {
        //        ConfigCode = this.RuleContext.ConfigInfo.ConfigCode,
        //        EnabledFlag = AutoMapper.Mapper.Map<string>(true)
        //    };
        //    string invalidMsg = string.Format("以下几列 [{0}] 组合，在数据库中已存在;", this.RuleContext.ConfigFieldInfos.Where(f => f.IsKey && f.IsVisible).Select(f => f.FieldName).ListToString());
        //    var importKeyCols = this.RuleContext.ConfigFieldInfos.Where(f => f.IsImportKey && f.IsVisible).Select(f => f.ValueColumnMap);
        //    if (data.TableName != "DWAPSDATA.APS_CM_CONFIG_DATA")
        //    {

        //        for (int i = 0; i < data.Rows.Count; i++)
        //        {
        //            StringBuilder sb = new StringBuilder();
        //            sb.Append(string.Format("SELECT ID FROM {0} WHERE 1=1 ", data.TableName));
        //            sb.Append(string.Format(" AND {0} != {1} ", Tencent.OA.FDW.CM.Entity.Mappings.ApsCmConfigDataTable.Id, this.RuleContext.FilterDataID.ToSafeInt(0)));
        //            List<string> extraCondList = new List<string>();
        //            DataRow row = data.Rows[i];

        //            foreach (var key in importKeyCols)
        //            {
        //                if (row[key] != null && !string.IsNullOrEmpty(row[key].ToSafeString()))
        //                {
        //                    sb.Append(string.Format(" AND {0} = '{1}' ", key, row[key]));
        //                }
        //                else
        //                {
        //                    sb.Append(string.Format(" AND {0} IS NULL ", key));
        //                }
        //            }

        //            var isHave = this.ConfigDataRepo.Exists(sb.ToString());
        //            if (isHave)
        //            {
        //                row[VerifyResultColumns.IsValid] = VerifyResultColumns.InvalidVal;
        //                row[VerifyResultColumns.Message] = row[VerifyResultColumns.Message].ToString() + invalidMsg;
        //                totalRepeated++;
        //            }
        //        }
        //    }
        //    else
        //    {

        //        if (importKeyCols != null && importKeyCols.Count() > 0)
        //        {
        //            DataTable distImportKeyTable = data.DefaultView.ToTable(true, importKeyCols.ToArray());
        //            for (int i = 0; i < distImportKeyTable.Rows.Count; i++)
        //            {
        //                foreach (var key in importKeyCols)
        //                {
        //                    searchCreteria[key] = distImportKeyTable.Rows[i][key];
        //                }
        //                CheckSameBatchBySearchCreteria(data, searchCreteria, invalidMsg);
        //            }
        //        }
        //        else
        //        {
        //            CheckSameBatchBySearchCreteria(data, searchCreteria, invalidMsg);
        //        }
        //    }
        //}

        //private void CheckSameBatchData(DataTable data)
        //{
        //    // 要获取同批次的数据，做主键校验，因为导入的值，和最终存入数据库的，有可能有：Text->Value的转换
        //    DataFormatter.InputFormat(RuleContext.ConfigInfo.RuleRefConfigCode, data);
        //    if (data.Rows.Count > 50)
        //    {
        //        DataBaseOfflineCheck(data);
        //    }
        //    else
        //    {
        //        DataBaseOnlineCheck(data);
        //    }
        //    DataFormatter.OutputFormat(RuleContext.ConfigInfo.RuleRefConfigCode, data);
        //}

        //private string GetSelectStr(DataRow row)
        //{
        //    string selectStr = string.Empty;
        //    var keyFieldList = this.RuleContext.ConfigFieldInfos.Where(f => f.IsKey && f.IsVisible);
        //    foreach (var field in keyFieldList)
        //    {
        //        if (DBNull.Value != row[field.ValueColumnMap])
        //        {
        //            Type fieldType = field.ToClrDataType();
        //            string tempStr = string.Empty;
        //            // SQL漏洞注入，参数化转义特殊字符'
        //            string value = row[field.ValueColumnMap].ToString();
        //            if (fieldType == typeof(string))
        //            {
        //                selectStr += string.Format(" AND {0}='{1}'", field.ValueColumnMap, value);
        //            }
        //            else if (fieldType == typeof(DateTime))
        //            {
        //                selectStr += string.Format(" AND {0}=#{1}#", field.ValueColumnMap, value);
        //            }
        //            else
        //            {
        //                selectStr += string.Format(" AND {0}={1}", field.ValueColumnMap, value);
        //            }
        //        }
        //        else
        //        {
        //            selectStr += string.Format(" AND {0} IS NULL", field.ValueColumnMap);
        //        }
        //    }

        //    if (!string.IsNullOrEmpty(selectStr))
        //    {
        //        selectStr = " 1=1 " + selectStr;
        //    }

        //    return selectStr;
        //}

        //private VerifyRuleResult VerifyInMemory()
        //{
        //    VerifyRuleResult VerifyRuleResult = new VerifyRuleResult();
        //    System.Data.DataTable data = this.RuleContext.TargetData;
        //    // hack:在  CaseSensitive=false时,select不区分中英文的的括号等;
        //    data.CaseSensitive = true;
        //    totalRepeated = 0;
        //    var fieldList = this.RuleContext.ConfigFieldInfos;
        //    if (fieldList != null && fieldList.Count() > 0)
        //    {
        //        var keyCols = fieldList.Where(f => f.IsKey && f.IsVisible).Select(f => f.ValueColumnMap);
        //        if (keyCols != null && keyCols.Count() > 0)
        //        {
        //            DataView dv = data.DefaultView;
        //            DataTable distKeyTable = dv.ToTable(true, keyCols.ToArray());
        //            // 如果是全量，不重复键的行数等于数据的总行数。则说明数据没有重复的。
        //            if (null != RuleContext && RuleContext.CurUserOpType == UserOperationType.ReplaceImport && distKeyTable.Rows.Count == data.Rows.Count)
        //            {
        //                // 主键校验通过
        //                VerifyRuleResult.IsValid = true;
        //            }
        //            else
        //            {
        //                string invalidMsg = string.Format("以下几列 [{0}] 组合，发现有重复数据;",
        //                   string.Join(",", fieldList.Where(f => f.IsKey && f.IsVisible).Select(f => f.FieldName).ToList()));
        //                foreach (DataRow row in distKeyTable.Rows)
        //                {
        //                    string selectStr = GetSelectStr(row);
        //                    if (!string.IsNullOrEmpty(selectStr))
        //                    {
        //                        try
        //                        {
        //                            var selectRows = data.Select(selectStr);
        //                            if (null != selectRows && selectRows.Count() > 1)
        //                            {
        //                                if (string.IsNullOrEmpty(VerifyRuleResult.Message))
        //                                {
        //                                    VerifyRuleResult.Message = invalidMsg;
        //                                }
        //                                foreach (DataRow invalidRow in selectRows)
        //                                {
        //                                    invalidRow[VerifyResultColumns.IsValid] = VerifyResultColumns.InvalidVal;
        //                                    invalidRow[VerifyResultColumns.Message] = invalidRow[VerifyResultColumns.Message].ToString() + invalidMsg;
        //                                    totalRepeated++;
        //                                }
        //                            }
        //                        }
        //                        catch (Exception ex)
        //                        {
        //                            //RuleContext.Log.Error("判断主键时，出错的select 语句：" + selectStr);
        //                            throw;
        //                        }
        //                    }
        //                }
        //                // 增量、新增、编辑、校验数据的校验
        //                if (null != RuleContext & RuleContext.CurUserOpType != UserOperationType.ReplaceImport)
        //                {
        //                    CheckSameBatchData(data);
        //                }
        //            }
        //        }
        //    }
        //    else
        //    {
        //        VerifyRuleResult.Message = "无法获取当前配置的字段定义;";
        //    }
        //    if (totalRepeated > 0)
        //    {
        //        if (RuleContext.CurUserOpType == UserOperationType.Add || RuleContext.CurUserOpType == UserOperationType.Update)
        //        {
        //            VerifyRuleResult.Message = "数据在数据库中已存在;";
        //        }
        //        else
        //        {
        //            VerifyRuleResult.Message = "发现有重复数据;";
        //        }
        //    }
        //    if (!VerifyRuleResult.IsValid)
        //    {
        //        RuleContext.MemoryUpdatedColList.Add(VerifyResultColumns.IsValid);
        //    }
        //    data.CaseSensitive = false;
        //    return VerifyRuleResult;
        //}

        private VerifyRuleResult VerifyInDB()
        {
            VerifyRuleResult result = new VerifyRuleResult
            {
                IsValid = true
            };
            var allKey = this.RuleContext.ConfigFieldInfos.Where(f => f.IsKey && f.IsVisible).ToList();
            if (allKey != null && allKey.Count > 0)
            {
                string invalidMsg = string.Format("以下几列 [{0}] 的组合已存在;", string.Join(",", allKey.Select(f => f.FieldName).ToList()));
                string updateTemplate = @"UPDATE  " + ConfigDataTableCheck.TableName + @"  D1
                                             SET D1.ISVALID = '{5}', D1.MESSAGE = CONCAT(COALESCE(D1.MESSAGE,''), '{4}')
                                           WHERE D1.RequestId = '{0}'
                                             AND D1.ConfigId = '{1}'
                                             AND EXISTS (SELECT 1
                                                           FROM ({2}) D2
                                                          WHERE 1=1 {3})";
                string d2Table = string.Empty;

                // 全量
                if (RuleContext.CurUserOpType == UserOperationType.ReplaceImport)
                {
                    //string keyCols = allKey.Select(k => this.RuleContext.MapToCheckCol(k.ValueColumnMap)).ListToString();
                    //d2Table = string.Format(@"SELECT {3}  FROM  {0}   WHERE RequestId = '{1}' AND ConfigId = '{2}' GROUP BY {3} HAVING COUNT(*) > 1 ", ConfigDataTableCheck.TableName, RuleContext.RequestId, RuleContext.ConfigInfo.ConfigCode, keyCols);
                }
                else
                {
                    var importKeyField = string.Join(",", RuleContext.ConfigFieldInfos.Where(f => f.IsImportKey).Select(f => f.ValueColumnMap).ToList());
                    var allKeyFieldName = string.Join(",", allKey.Select(f => f.ValueColumnMap).ToList());
                    var allAliaKeyFieldName = string.Join(",", allKey.Select(f => "A." + f.ValueColumnMap + " as " + f.ValueColumnMap).ToList());
                    StringBuilder d2TableSub2Sel = new StringBuilder();
                    d2TableSub2Sel.AppendFormat(@" SELECT {0}", allAliaKeyFieldName);
                    StringBuilder d2TableSub2From = new StringBuilder();
                    d2TableSub2From.AppendFormat(@"  FROM {0} A ", this.RuleContext.ConfigInfo.DataTable);
                    StringBuilder d2TableSub2Where = new StringBuilder();
                    d2TableSub2Where.AppendFormat(@" WHERE 1=1 AND A.ConfigId='{0}' ", this.RuleContext.ConfigInfo.Id);

                    //if (string.IsNullOrEmpty(importKeyField))
                    //{
                    //    d2TableSub2Where.AppendFormat(@" AND NOT EXISTS ( SELECT 1 FROM  {0} C WHERE C.RequestId = '{1}' AND C.ConfigId='{2}' AND C.ID > 0 AND A.ID = C.ID )", ConfigDataTableCheck.TableName, RuleContext.RequestId, RuleContext.ConfigInfo.Id);
                    //}
                    //else
                    //{
                    //    var aliaImportKeyField = string.Join(",", RuleContext.ConfigFieldInfos.Where(f => f.IsImportKey).Select(f => "A." + f.ValueColumnMap).ToList());
                    //    d2TableSub2Where.AppendFormat(@" AND NOT EXISTS ( SELECT 1 FROM  {0} C WHERE C.RequestId = '{1}' AND C.ID > 0 AND A.ID = C.ID )
                    //                                 AND ({3}) IN (SELECT DISTINCT {4}    FROM  {0}   WHERE RequestId ='{1}' AND ConfigId = '{2}' ) ",
                    //                                    ConfigDataTableCheck.TableName, RuleContext.RequestId, RuleContext.ConfigInfo.Id, aliaImportKeyField, importKeyField);
                    //}

                    //this.DataFormatter.ConvertSqlValToText(this.RuleContext.ConfigFieldInfos, this.RuleContext.StoreCheckColMap, d2TableSub2Sel, d2TableSub2From, d2TableSub2Where, "A");
                    string d2UnionData = d2TableSub2Sel.Append(d2TableSub2From).Append(d2TableSub2Where).ToString();
                    d2Table = string.Format(@"SELECT  {3} FROM( SELECT  {3} FROM  {0}  WHERE RequestId = '{1}' AND ConfigId = '{2}'  UNION ALL {4} )TAB GROUP BY {3} HAVING COUNT(*) > 1",
                                            ConfigDataTableCheck.TableName, RuleContext.RequestId, RuleContext.ConfigInfo.Id, allKeyFieldName, d2UnionData);
                }

                string crossCond = string.Empty;
                //foreach (var field in allKey)
                //{
                //    crossCond += string.Format(" AND NVL({0}.{2},-999999) = NVL({1}.{2},-999999) ", "D1", "D2", this.RuleContext.StoreCheckColMap[field.ValueColumnMap]);
                //}

                string updateSql = string.Format(updateTemplate, RuleContext.RequestId, RuleContext.ConfigInfo.Id, d2Table, crossCond, invalidMsg, VerifyResultColumns.InvalidVal);
                var unitOfWork = RuleContext.ServiceProvider.GetRequiredService<IUnitOfWork>();
                var updatedRows = unitOfWork.Connection.Execute(updateSql);

                if (updatedRows > 0)
                {
                    result.IsValid = false;
                    RuleContext.DbUpdatedColList.Add(VerifyResultColumns.IsValid);
                    if (RuleContext.CurUserOpType == UserOperationType.Add || RuleContext.CurUserOpType == UserOperationType.Update)
                    {
                        result.Message = "当前数据在数据库中已存在;";
                    }
                    else
                    {
                        result.Message = "在Excel或数据库中发现有重复数据;";
                    }
                }
            }

            return result;
        }
    }
}
